<?php

/**
 * Created by PhpStorm.
 * User: longli
 * VX: isa1589518286
 * Date: 2020/11/21
 * Time: 18:45
 * @link http://www.lmterp.cn
 */

namespace app\common\service\channel;

use app\common\library\Tools;
use app\common\model\Channel;
use app\common\model\ChannelOrders;
use app\common\model\Orders;
use app\common\service\logistics\ChannelService;
use think\facade\Log;

/**
 * 易通关
 * Class YiTongGuan
 * @package app\common\service\channel
 */
class YiTongGuan extends BaseChannel
{
    public static $tokenField = [
        'required' => [ // 必填字段
            [
                'type' => 'text',
                'name' => 'companyID',
                'field' => 'companyID',
            ],
            [
                'type' => 'text',
                'name' => 'pwd',
                'field' => 'pwd',
            ]
        ],
        'option' => [ // 可选字段
        ],
    ];

    public function getTrackNumber()
    {
        $apvalues = $apweights = $apdescriptions = $customsArticleNames = $sku = [];
        foreach($this->order->detail as $detail)
        {
            $sku[] = $detail->sku;
            $apvalues[] = $detail->declare_price;
            $apweights[] = $detail->declare_weight > 0 ? $detail->declare_weight / 1000 : 1;
            $apdescriptions[] = $detail->declare_ch;
            $customsArticleNames[] = $detail->declare_en;
        }
        $params = [
            'parcelList' => [
                'apmethod' => $this->channel->channel_code, // 运输方式
                'apname' => Orders::getBuyerName($this->order), // 收件人姓名
                'apaddress' => $this->order->buyer_address_1, // 地址1
                'address2' => $this->order->buyer_address_2, // 地址2
                'apdestination' => $this->order->buyer_country_code, // 目的国家(二字代码)
                'city' => $this->order->buyer_city, // 城市
                'province' => $this->order->buyer_province, // 州/省
                'apnote' => '', // 备注信息
                'apquantitys' => 1, // 商品各类
                'apTel' => Orders::getBuyerPhone($this->order), // 收件人电话
                'zipCode' => $this->order->buyer_post_code, // 邮编
                'sku' => join(";", $sku), // sku
                'refNo' => $this->order->order_sn, // 参考号(客户参考号不能重复)
                'apvalues' => join(";", $apvalues), // 价值 (每个物品价格)多个价值，采用分号分隔
                'apweights' => join(";", $apweights), // 多个重量，采用分号分隔
                'apdescriptions' => join(";", $apdescriptions), // 多个物品，采用分号分隔 例：单品物品1; 单品物品2
                'customsArticleNames' => join(";", $customsArticleNames), // 报关品名信息Length < =200 ,多个报关品名，采用分号分隔, 英文名称
                'actualWeight' => $this->order->weight > 0 ? $this->order->weight / 1000 : '0', // 实际重量, 没有填写0
            ]
        ];

        $data = $this->request($params, 'addParcelAndForecastService');
        if($this->hasError($data))
        {
            $this->order->order_status = Orders::ORDER_DECLARE_ERROR;
            $this->order->save();
            return false;
        }
        $track = trim($data['trackingNo']);
        $this->order->save([
            'track_num'      => $track,
            'order_status'   => Orders::ORDER_DECLARE_SUCC,
            'track_num_time' => Tools::now(),
            'logistics_name' => $this->channel->carrier->carrier_name,
        ]);
        ChannelService::getInstance()->saveChannelOrders([
            'order_id' => $this->order->order_id,
            'logistics_sn' => trim($data['vsnumber']),
            'channel_id' => $this->channel->channel_id,
            'country_code' => $this->order->buyer_country_code,
            'track_num' => $track,
            'weight' => $this->order->weight,
        ]);
        return $track;
    }

    /**
     * @inheritDoc
     */
    public function getLabel()
    {
        if(empty($this->order->track_num)) return false;
        $lable = "Label_{$this->channel->label_width}_{$this->channel->label_height}";
        $params = [
            'apUserId'=> $this->channel->carrier->token->companyID,
            'apTrackingNo' => $this->order->track_num,
            'abOrder' => '',
            'abOrderType' => '',
            'abColset' => 'Y',
            'printNumber' => '6',
            'sellerID' => '1',
            'pageType' => $lable,
            'buyerID' => '0',
            'printPosition' => '0',
            'consignor' => '1',
            'prTime' => '0',
            'itemTitle' => '0',
            'bglabel' => '1',
            'mergePrint' => '1',
            'refNo' => '0',
            'sysAccount' => '1',
            'barcodePrint' => '0',
            'printType' => 'pdf',
            'fontSize' => '8',
            'peihuo' => 0,
        ];
        $url = 'http://sys.etg56.com/apiLabelPrint/freemarkerPrint?'. http_build_query($params);
        $byte = file_get_contents($url);
        if(empty($byte))
        {
            $this->order->order_status = Orders::ORDER_LABEL_ERROR;
            $this->order->save();
            return false;
        }
        $this->order->label_url = self::saveLabel($byte);
        $this->order->save();
        ChannelService::getInstance()->saveChannelOrders([
            'order_id' => $this->order->order_id,
            'channel_id' =>$this->channel->channel_id,
            'track_num' => $this->order->track_num,
            'label_url' => $this->order->label_url,
        ]);
        return $this->order->label_url;
    }

    public function cancelOrder()
    {
        $params = [
            'refNos' => $this->order->order_sn
        ];
        $data = $this->request($params, 'deleteParcelByRefNoService');
        if($this->hasError($data)) return false;
        ChannelService::getInstance()->saveChannelOrders([
            'order_id' => $this->order->order_id,
            'channel_id' =>$this->channel->channel_id,
            'track_num' => $this->order->track_num,
            'is_cancel' => ChannelOrders::IS_YES,
        ]);
        return true;
    }

    /**
     * 解析 xml 为数组
     * @param string $xml xml 字符串
     * @return array
     */
    protected function parseXML($xml)
    {
        $tag = 'return';
        $xml = substr($xml, strpos($xml,"<$tag>"));
        $xml = substr($xml, 0, strpos($xml,"</$tag>") + strlen("</$tag>"));
        return Tools::xmlToArray($xml);
    }

    /**
     * 是否包含错误信息
     * @param array $data
     * @return bool
     */
    protected function hasError($data = [])
    {
        if($data['errorCode'] != 0 || $data['success'] == 'false')
        {
            Log::info(sprintf("渠道【%s】响应错误，错误信息【%s】, 订单号【%s】", $this->channel->channel_name, $data['errorMsg'], $this->order->order_sn));
            return true;
        }
        return false;
    }

    /**
     * 发起 Soap 请求
     * @param array $postData 请求的数据
     * @param string $service 请求的服务
     * @return array
     * @throws \SoapFault
     */
    protected function request($postData, $service)
    {
        $xml = $this->buildBody($postData, $service);
        $client = new \SoapClient($this->channel->carrier->api_base_url);
        $result = $client->__doRequest($xml, $this->channel->carrier->api_base_url, $service, 1, 0);
        return $this->parseXML($result);
    }

    /**
     * 构建请求体
     * @param array $postData 请求体
     * @param string $service 请求的服务
     * @return string
     * @date 2020/11/21
     * @author longli
     */
    protected function buildBody($postData = [], $service = '')
    {
        $xml = <<<EOF
<?xml version="1.0" encoding="UTF-8" ?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>%s</soap:Body>
</soap:Envelope>
EOF;
        $postData = array_merge([
            'companyID' => $this->channel->carrier->token->companyID,
            'pwd' => $this->channel->carrier->token->pwd,
            ], $postData);
        $body = Tools::arrayToXml($postData, ['name' => "ns:$service", 'attribute' => ['xmlns:ns' => 'http://cxf.pl/']]);
        return sprintf($xml, explode("\n", $body)[1]);
    }
}